﻿using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;
using Yonkly.Fitlers;
using Yonkly.Models;
using Yonkly.Services;
using Yonkly.Utility;
using JsonResult = Yonkly.Models.JsonResult;

namespace Yonkly.Controllers
{
    public interface IMessageController
    {
    }

    public class MessageController : BaseController
    {
        #region Actions

        public ActionResult Conversation(long Id, int? page)
        {
            return View("Conversation", GetConversationData(Id, page));
        }


        public ActionResult PostPic()
        {
            //System.Drawing.Image thumbnail_image = null;
            System.Drawing.Image original_image = null;
            System.Drawing.Image thumbnailImage = null;
            System.Drawing.Graphics graphic = null;
            //MemoryStream ms = null;

            try
            {
                string filepath = Server.MapPath("~/content/uploads/");
                string baseFilename = Guid.NewGuid().ToString();// DateTime.Now.ToString("yyyyMMddHHmmssfff");
                string filename = string.Format("{0}.jpg", baseFilename);
                string filename_th = string.Format("{0}_th.jpg", baseFilename);
                // Get the data
                var jpeg_image_upload = Request.Files["Filedata"];

                // Retrieve the uploaded image
                original_image = System.Drawing.Image.FromStream(jpeg_image_upload.InputStream);
                //original_image.Save(filename, ImageFormat.Jpeg);
                AmazonHelper.UploadFile(Globals.AmazonBucketName, filename, null, original_image.ToByteArray(ImageFormat.Jpeg));

                /* // Calculate the new width and height
                 int width = original_image.Width;
                 int height = original_image.Height;
                 int target_width = 100;
                 int target_height = 100;
                 int new_width, new_height;

                 float target_ratio = (float)target_width / (float)target_height;
                 float image_ratio = (float)width / (float)height;

                 if (target_ratio > image_ratio)
                 {
                     new_height = target_height;
                     new_width = (int)Math.Floor(image_ratio * (float)target_height);
                 }
                 else
                 {
                     new_height = (int)Math.Floor((float)target_width / image_ratio);
                     new_width = target_width;
                 }

                 new_width = new_width > target_width ? target_width : new_width;
                 new_height = new_height > target_height ? target_height : new_height;


                 // Create the thumbnail

                 // Old way
                 //thumbnail_image = original_image.GetThumbnailImage(new_width, new_height, null, System.IntPtr.Zero);
                 // We don't have to create a Thumbnail since the DrawImage method will resize, but the GetThumbnailImage looks better
                 // I've read about a problem with GetThumbnailImage. If a jpeg has an embedded thumbnail it will use and resize it which
                 //  can result in a tiny 40x40 thumbnail being stretch up to our target size


                 thumbnailImage = new System.Drawing.Bitmap(target_width, target_height);
                 graphic = System.Drawing.Graphics.FromImage(thumbnailImage);
                 graphic.FillRectangle(new System.Drawing.SolidBrush(System.Drawing.Color.Black), new System.Drawing.Rectangle(0, 0, target_width, target_height));
                 int paste_x = (target_width - new_width) / 2;
                 int paste_y = (target_height - new_height) / 2;
                 graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; // new way 
                 //graphic.DrawImage(thumbnail_image, paste_x, paste_y, new_width, new_height);
                 graphic.DrawImage(original_image, paste_x, paste_y, new_width, new_height);

                 */

                thumbnailImage = original_image.GetThumbnailImage(100, (int)((100.0 / original_image.Width) * original_image.Height),
                                                                  ThumbnailCallback, IntPtr.Zero);

                //final_image.Save(filename_th, ImageFormat.Jpeg);
                AmazonHelper.UploadFile(Globals.AmazonBucketName, filename_th,
                    null, thumbnailImage.ToByteArray(ImageFormat.Jpeg));


                Response.StatusCode = 200;
                Response.Write(string.Format("{0}_th.jpg", baseFilename));

                //create db record
                //string imageUrl = string.Format("{0}/content/uploads/", Globals.SiteUrl);
                //string imageUrl = AmazonHelper.GetFileUrl(Globals.AmazonBucketName, filename);
                //string imageThumbUrl = AmazonHelper.GetFileUrl(Globals.AmazonBucketName, filename_th);

                //Create(string.Format("{0}{1}.jpg", imageUrl, baseFilename),
                //       string.Format("{0}{1}_th.jpg", imageUrl, baseFilename), (int?)MessageTypes.Image, null);

                var result = Create(" ", baseFilename,
                        (int?)MessageTypes.Image, null);

                if (result == null || ((JsonData)result.Data).isSuccessful == false)
                {
                    try
                    {
                        AmazonHelper.Delete(filename);
                        AmazonHelper.Delete(filename_th);
                    }
                    catch (Exception)
                    {
                    }
                }
            }
            catch
            {
                // If any kind of error occurs return a 500 Internal Server error
                Response.StatusCode = 500;
                Response.Write("An error occured");
                //Response.End();
            }
            finally
            {
                // Clean up
                if (thumbnailImage != null) thumbnailImage.Dispose();
                if (graphic != null) graphic.Dispose();
                if (original_image != null) original_image.Dispose();
                //if (thumbnail_image != null) thumbnail_image.Dispose();
                //if (ms != null) ms.Close();
                Response.End();
            }


            return Json(new object());
        }


        public System.Web.Mvc.JsonResult Create(string message, string baseImageFilename, int? type, long? ParentId)
        {
            type = type ?? (int?)MessageTypes.Text;
            var result = new JsonData();
            if (string.IsNullOrEmpty(message))
            {
                result.isSuccessful = false;
                result.errorMessage = "Message cannot be blank.";
            }
            else
            {
                //update the database
                if (IsUserAuthenticated)
                {
                    try
                    {
                        using (YonklyDataContext dc = new YonklyDataContext())
                        {
                            Regex UrlExpression =
                                new Regex(
                                    @"((http|ftp|https):\/\/)?[\w\-_]+(\.[\w\-_]+)*([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
                            //message = UrlExpression.Replace(message, match =>
                            //                                string.Format("http://yonkly.com/link/{0}",
                            //                                              LinkController.CreateLink(
                            //                                                  match.ToString())));

                            //message = UrlExpression.Replace(message, match =>
                            //                                string.Format("http://yonkly.com/link/{0}",
                            //                                              LinkController.CreateLink(
                            //                                                  match.ToString())));

                            //message = UrlExpression.Replace(message, match => Utils.MakeTinyUrl(match.ToString()));

                            var msg = new Message
                                          {
                                              Text = message.Replace("\r\n", " "),
                                              ModifiedOn = DateTime.Now.ToUniversalTime(),
                                              CreatedOn = DateTime.Now.ToUniversalTime(),
                                              SenderId = LoggedInUserId,
                                              Type = ((int)type),
                                              Source = "yonkly"
                                          };

                            if (!string.IsNullOrEmpty(baseImageFilename))
                            {
                                //todo refactor filename constructions
                                msg.ImageFilename = string.Format("{0}.jpg", baseImageFilename);
                                msg.ThumbnailFilename = string.Format("{0}_th.jpg", baseImageFilename);
                            }
                            if (ParentId != null)
                            {
                                msg.ParentId = ParentId;
                            }
                            dc.Messages.InsertOnSubmit(msg);
                            dc.SubmitChanges();

                            if (type == (int?)MessageTypes.Text)
                            {
                                UpdateTwitter(message);
                            }

                            result.Id = msg.MessageId.ToString();

                            try
                            {
                                if (ParentId != null)
                                {
                                    var parentMessage = dc.Messages.First(m => m.MessageId == ParentId);
                                    var notifyparent = ProfileController.GetUserSettings(parentMessage.SenderId).ReceiveEmailOnResponse;
                                    if (notifyparent)
                                    {
                                        SendResponseNotification(parentMessage.Sender.Membership.Email, (long)ParentId, parentMessage.Sender.UserName, msg.Text);
                                    }
                                }
                            }
                            catch (Exception)
                            {
                                //ignore send email errors
                                //todo need to log this
                            }
                        }
                        result.isSuccessful = true;
                    }
                    catch
                    {
                        result.isSuccessful = false;
                        result.errorMessage = "Failed to save message.";
                    }
                }
                else
                {
                    result.isSuccessful = false;
                    result.errorMessage = "You must be logged in to post a message";
                }
            }
            return Json(result);
        }

        public ActionResult Reply(long MessageId, string Message)
        {
            return Create(Message, string.Empty, (int?)MessageTypes.Text, MessageId);
        }

        public ActionResult Delete(long messageId)
        {
            JsonResult result = new JsonResult();
            try
            {
                //delete message from database
                //make sure the user has the right to delete
                using (YonklyDataContext dc = new YonklyDataContext())
                {
                    //get the message
                    var message = dc.Messages.Where(m => m.MessageId == messageId
                                                         && m.SenderId == LoggedInUserId).First();

                    if (message != null)
                    {
                        if (dc.ViewMessages.First(m => m.MessageId == messageId).ChildrenCount > 0)
                        {
                            result.isSuccessful = false;
                            result.errorMessage = "You cannot delete messages that have been replied to.";
                        }
                        else
                        {
                            if (message.Type == (int)MessageTypes.Image)
                            {
                                //delete the files
                                try
                                {
                                    AmazonHelper.Delete(message.ImageFilename); //image
                                    AmazonHelper.Delete(message.ThumbnailFilename); //thumbnail
                                }
                                catch (Exception ex)
                                {
                                    Utils.Log(ex);
                                }
                            }
                            dc.Messages.DeleteOnSubmit(message);
                            dc.SubmitChanges();
                            result.isSuccessful = true;
                            result.errorMessage = "Message deleted.";
                        }
                    }
                    else
                    {
                        result.isSuccessful = false;
                        result.errorMessage = "Message already deleted or you don't have permission to delete it.";
                    }
                }
            }
            catch (Exception)
            {
                result.isSuccessful = false;
                result.errorMessage = "Unexpected error while deleting message.";
            }
            return View("Json", result);
        }

        public ActionResult FriendsMessages(string username, int? page)
        {
            page = page ?? 0;
            if (string.IsNullOrEmpty(username))
            {
                return RedirectToAction("Index", "Home");
            }
            else
            {
                if (UserManager.GetUser(username, false) == null)
                {
                    return View("Error", GetBaseViewData());
                }
                else
                {
                    return View("Friends", GetFriendsMessagesViewData(username, page));
                }
            }
        }

        public ActionResult Messages(string username, int? page)
        {
            page = page ?? 0;
            if (string.IsNullOrEmpty(username))
            {
                return RedirectToAction("Index", "Home");
            }
            else
            {
                if (UserManager.GetUser(username, false) == null)
                {
                    return View("Error", GetBaseViewData());
                }
                else
                {
                    return View("Messages", GetMessagesViewData(username, page));
                }
            }
        }

        public ActionResult Replies(string username, int? page)
        {
            page = page ?? 0;
            if (string.IsNullOrEmpty(username))
            {
                return RedirectToAction("Index", "Home");
            }
            else
            {
                if (UserManager.GetUser(username, false) == null)
                {
                    return View("Error", GetBaseViewData());
                }
                else
                {
                    return View("Replies", GetRepliesViewData(username, page));
                }
            }
        }

        public ActionResult RefreshMessages(string username)
        {
            return View("recentmessages", GetMessagesViewData(username, null));
            //return Messages(((BaseViewData)ViewData.Model).CurrentUser.UserName, null);
        }

        //protected override void HandleUnknownAction(string actionName)
        //{
        //    RenderView("Error");
        //}

        #endregion



        #region Private/Protected Methods
        private bool ThumbnailCallback()
        {
            return true;
        }

        private void UpdateTwitter(string message)
        {
            try
            {
                var us = ProfileController.GetUserSettings(LoggedInUserId);
                if (!string.IsNullOrEmpty(us.TwitterUserName) && !string.IsNullOrEmpty(us.TwitterPassword))
                {
                    Twitter tw = new Twitter();
                    var xml = tw.UpdateAsXML(us.TwitterUserName, us.TwitterPassword, message);
                }
            }
            catch (Exception e)
            {
                Utils.Log(e);
            }
        }

        private MessagesViewData GetRepliesViewData(string username, int? page)
        {
            var viewData = new MessagesViewData(GetBaseViewData(username));

            //get messages
            using (var dc = new YonklyDataContext())
            {
                Guid userid = (Guid)UserManager.GetUser(username, false).ProviderUserKey;
                var friendmessages = from parentMessages in dc.ViewMessages
                                     join childmessages in dc.ViewMessages on parentMessages.MessageId equals childmessages.ParentId
                                     where parentMessages.SenderId == userid
                                     select childmessages;

                var query = (from messages in friendmessages
                             select new MessageItem(viewData, messages) { CreatedOn = messages.CreatedOn }
                            ).OrderByDescending(m => m.CreatedOn);

                viewData.Messages = query.ToPagedList((int)page, Globals.PageSize);
            }
            return viewData;
        }

        protected MessagesViewData GetMessagesViewData(string username, int? page)
        {
            page = page ?? 0;
            var viewData = new MessagesViewData(GetBaseViewData(username));

            //get user messages
            using (var dc = new YonklyDataContext())
            {
                var mymessages = from messages in dc.ViewMessages
                                 where messages.SenderId == viewData.CurrentUser.UserId ||
                                       messages.RecipientId == viewData.CurrentUser.UserId
                                 select messages;


                var query = (from messages in mymessages
                             select new MessageItem(viewData, messages) { CreatedOn = messages.CreatedOn }
                            ).OrderByDescending(m => m.CreatedOn);

                viewData.Messages = query.ToPagedList((int)page, Globals.PageSize);
            }
            return viewData;
        }

        private MessagesViewData GetFriendsMessagesViewData(string username, int? page)
        {
            var viewData = new MessagesViewData(GetBaseViewData(username));

            //get messages
            using (var dc = new YonklyDataContext())
            {
                Guid userid = (Guid)UserManager.GetUser(username, false).ProviderUserKey;
                var friendmessages = from messages in dc.ViewMessages
                                     join friends in dc.Friends on messages.SenderId equals friends.FriendId
                                     where friends.UserId == userid
                                     select messages;

                var query = (from messages in friendmessages
                             select new MessageItem(viewData, messages) { CreatedOn = messages.CreatedOn }
                            ).OrderByDescending(m => m.CreatedOn);

                viewData.Messages = query.ToPagedList((int)page, Globals.PageSize);
            }
            return viewData;
        }
        private void SendResponseNotification(string email, long parentMessageId, string username, string message)
        {
            try
            {
                const string CacheKey = "responseMailTemplate";

                string body = HttpContext.Cache[CacheKey] as string;

                if (body == null)
                {
                    string file = System.Web.HttpContext.Current.Server.MapPath("~/content/MailTemplates/replyreceived.txt");
                    body = File.ReadAllText(file);

                    if (HttpContext.Cache[CacheKey] == null)
                    {
                        HttpContext.Cache[CacheKey] = body;
                    }
                }
                string originalMessage;
                using (var dc = new YonklyDataContext())
                {
                    originalMessage = dc.Messages.First(m => m.MessageId == parentMessageId).Text;
                }

                body = body.Replace("<%username%>", username);
                body = body.Replace("<%responder%>", LoggedInUserName);
                body = body.Replace("<%conversation%>", "http://yonkly.com/message/conversation/" + parentMessageId);
                body = body.Replace("<%responderUrl%>", string.Format("{0}/{1}", Globals.SiteUrl, LoggedInUserName));
                body = body.Replace("<%message%>", message);
                body = body.Replace("<%original_message%>", originalMessage);

                SendMail(email, "Yonkly.com: New Reply", body);
            }
            catch
            {
                //ignore email errors
                //todo need to log these errors
            }
        }

        private ConversationViewData GetConversationData(long id, int? page)
        {
            page = page ?? 0;
            var data = new ConversationViewData(GetBaseViewData(), page) { Id = id };
            return data;
        }
        #endregion
    }
}